package com.tancire.sources.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.tancire.common.enums.UserSource;
import com.tancire.common.exception.ResourceException;
import com.tancire.common.utils.DateUtils;
import com.tancire.common.utils.SecurityUtils;
import com.tancire.common.utils.StringUtils;
import com.tancire.common.utils.TcStrUtils;
import com.tancire.common.utils.file.FileUtils;
import com.tancire.common.utils.sources.SourceUtils;
import com.tancire.file.bean.SaveFileBean;
import com.tancire.file.service.ISysFileService;
import com.tancire.framework.web.service.HeaderService;
import com.tancire.sources.domain.SourceAuth;
import com.tancire.sources.domain.SourceCode;
import com.tancire.sources.domain.SurFile;
import com.tancire.sources.domain.WriteFile;
import com.tancire.sources.mapper.SurFileMapper;
import com.tancire.sources.service.ISurFileService;
import com.tancire.sources.utils.WriteFileUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import static com.tancire.common.constant.SourceConst.ROOT_DIR_ID;
import static com.tancire.common.utils.file.MimeTypeUtils.FOLDER_TYPE;
import static com.tancire.common.utils.file.MimeTypeUtils.UNKNOWN_TYPE;

/**
 * 文件管理Service业务层处理
 *
 * @author chenchao
 * @date 2024-08-18
 */
@Slf4j
@Service
public class SurFileServiceImpl implements ISurFileService {

    @Resource
    private SurFileMapper surFileMapper;

    @Resource
    private ISysFileService sysFileService;

    @Resource
    private WriteFileUtils writeFileUtils;

    @Resource
    private HeaderService headerService;

    /**
     * 查询文件管理
     *
     * @param id 文件管理主键
     * @return 文件管理
     */
    @Override
    public SurFile selectSurFileById(Long id) {
        return surFileMapper.selectSurFileById(id);
    }

    /**
     * 查询文件管理列表
     *
     * @param surFile 文件管理
     * @return 文件管理
     */
    @Override
    public List<SurFile> selectSurFileList(SurFile surFile) {
        UserSource source = headerService.getSource();
        if (UserSource.MEMBER.equals(source)) {
            // 会员 必须注入会员ID
            surFile.setCreateBy(SecurityUtils.getUserId() + "");
        }
        surFile.setUserSource(source.getCode());
        return surFileMapper.selectSurFileList(surFile);
    }

    /**
     * 新增文件管理
     *
     * @param surFile 文件管理
     * @return 结果
     */
    @Override
    public int insertSurFile(SurFile surFile) {
        surFile.setCreateTime(DateUtils.getNowDate());
        surFile.setCreateBy(SecurityUtils.getUserId() + "");
        int currentUserSource = headerService.getCurrentUserSource();
        surFile.setUserSource(currentUserSource);
        // 处理父节点
        this.handleParentId(surFile);
        //
        if (0 == surFile.getFileCategory()) {
            surFile.setFileType(FOLDER_TYPE);
        }
        // 保存数据
        return surFileMapper.insertSurFile(surFile);
    }

    /**
     * 处理父节点信息
     *
     * @param surFile
     */
    private void handleParentId(SurFile surFile) {
        Long pid = surFile.getPid();
        if (null == pid || ROOT_DIR_ID == pid) {
            surFile.setPid(ROOT_DIR_ID);
            surFile.setPids("");
        } else {
            SurFile parentNode = surFileMapper.selectSurFileById(pid);
            String pids = parentNode.getPids();
            surFile.setPids(TcStrUtils.joinStr(pids, pid.toString()));
        }
    }

    /**
     * 修改文件管理
     *
     * @param surFile 文件管理
     * @return 结果
     */
    @Override
    public int updateSurFile(SurFile surFile) {
        surFile.setUpdateTime(DateUtils.getNowDate());
        UserSource source = headerService.getSource();
        if (UserSource.MEMBER.equals(source)) {
            SurFile surFileHis = surFileMapper.selectSurFileById(surFile.getId());
            String userIdStr = SecurityUtils.getUserId() + "";
            if (!userIdStr.equals(surFileHis.getCreateBy())) {
                throw new ResourceException("您无权限修改当前文件名称");
            }
        }
        return surFileMapper.updateSurFile(surFile);
    }

    /**
     * 批量删除文件管理
     *
     * @param ids 需要删除的文件管理主键
     * @return 结果
     */
    @Override
    public int deleteSurFileByIds(Long[] ids) {
        // 需要删除对应文件
        for (Long id : ids) {
            // 获取详情
            SurFile surFile = surFileMapper.selectSurFileById(id);
            if (SourceUtils.isDir(surFile.getFileCategory())) {
                List<SurFile> surFiles = surFileMapper.selectChildNodeList(id);
                this.removeFileList(surFiles);
            } else {
                // 删除文件
                sysFileService.deleteFile(surFile.getFilePath(), "Y");
            }
        }
        return surFileMapper.deleteSurFileByIds(ids);
    }

    /**
     * 移除文件列表
     *
     * @param surFiles
     */
    private void removeFileList(List<SurFile> surFiles) {
        if (ObjectUtil.isNotEmpty(surFiles)) {
            for (SurFile surFile : surFiles) {
                if (!SourceUtils.isDir(surFile.getFileCategory())) {
                    // 非目录删除文件
                    sysFileService.deleteFile(surFile.getFilePath(), "Y");
                }
                surFileMapper.deleteSurFileById(surFile.getId());
            }
        }
    }

    /**
     * 删除文件管理信息
     *
     * @param id 文件管理主键
     * @return 结果
     */
    @Override
    public int deleteSurFileById(Long id) {
        return surFileMapper.deleteSurFileById(id);
    }

    /**
     * 获取子节点
     *
     * @param pid
     * @return
     */
    @Override
    public List<SurFile> getChildNode(Long pid) {
        SurFile surFile = new SurFile();
        surFile.setPid(pid);
        surFile.setCreateBy(SecurityUtils.getUserId().toString());
        surFile.setUserSource(headerService.getCurrentUserSource());
        return surFileMapper.selectSurFileList(surFile);
    }

    @Transactional
    @Override
    public void moveDirOrFile(List<SurFile> surFileList) {
        // 校验是否可以移动 先查询所有子节点
        for (SurFile file : surFileList) {
            this.moveDir(file);
        }
    }

    @Override
    public void copyDirOrFile(List<SurFile> surFileList) {
        // 复制目录
    }

    /**
     * 获取临时授权码
     *
     * @param id
     * @return
     */
    @Override
    public SourceCode getViewCode(Long id) {
        SourceCode res = new SourceCode();
        res.setAuthStatus(0);
        SurFile surFile = this.surFileMapper.selectSurFileById(id);
        // 其他校验等
        Integer fileCategory = surFile.getFileCategory();
        if (null == fileCategory || 0 == fileCategory) {
            res.setAuthStatus(1);
            res.setMsg("目录不能获取播放授权码");
            return res;
        }
        // 生成code
        String code = writeFileUtils.generateCode(surFile.getId());
        res.setAuthCode(code);
        return res;
    }

    @Override
    public SaveFileBean uploadFile(MultipartFile file, Long dirId, Integer userSource) {
        SurFile parentDir = surFileMapper.selectSurFileById(dirId);
        Integer fileCategory = parentDir.getFileCategory();
        if (null != fileCategory && 1 == fileCategory) {
            throw new ResourceException("文件只能上传到文件夹下");
        }
        try {
            SaveFileBean saveFileBean = sysFileService.uploadFile(file, "Y");
            String fileName = saveFileBean.getFileName();
            // 初始化数据库保存数据
            SurFile surFile = new SurFile();
            surFile.setFilePath(fileName);
            surFile.setPid(dirId);
            surFile.setPids(TcStrUtils.joinStr(parentDir.getPids(), parentDir.getId().toString()));
            surFile.setFileSize(saveFileBean.getFileSize());
            surFile.setFileName(FileUtils.getNameNotSuffix(file.getOriginalFilename()));
            String fileExtName = FileUtils.getFileExtName(fileName);
            surFile.setFileType(StringUtils.isBlank(fileExtName) ? UNKNOWN_TYPE : fileExtName);
            surFile.setFileSort(1);
            surFile.setCreateTime(new Date());
            surFile.setCreateBy(SecurityUtils.getUserId().toString());
            surFile.setFileCategory(1);
            surFile.setUserSource(userSource);
            this.surFileMapper.insertSurFile(surFile);
            return saveFileBean;
        } catch (Exception e) {
            throw new ResourceException("上传资源文件异常");
        }
    }

    @Override
    public void view(String code, HttpServletRequest req, HttpServletResponse res) {
        SourceAuth sourceAuth = writeFileUtils.checkAuth(code);
        SurFile surFile = this.surFileMapper.selectSurFileById(sourceAuth.getId());
        writeFileUtils.view(new WriteFile(surFile.getFileName(), surFile.getFilePath(), surFile.getFileSize(), surFile.getFileType()), req, res);
    }

    @Override
    public void download(String code, HttpServletRequest req, HttpServletResponse res) {
        SourceAuth sourceAuth = writeFileUtils.checkAuth(code);
        SurFile surFile = this.surFileMapper.selectSurFileById(sourceAuth.getId());
        writeFileUtils.write(new WriteFile(surFile.getFileName(), surFile.getFilePath(), surFile.getFileSize(), surFile.getFileType()), res);
    }

    private void moveDir(SurFile file) {
        // 获取所有子节点
        List<SurFile> childNodeList = this.surFileMapper.selectChildNodeList(file.getId());
        // 判断是否可以移动
        Long pid = file.getPid();
        long count = childNodeList.stream().filter(x -> Objects.equals(x.getPid(), pid)).count();
        if (count > 0 || Objects.equals(pid, file.getId())) {
            throw new ResourceException("移动文件不能是其子目录和它自己");
        }
        // 判断父节点是不是目录
        if (null != pid && 0 != pid) {
            SurFile parent = this.surFileMapper.selectSurFileById(pid);
            if (parent.getFileCategory() != 0) {
                throw new ResourceException("必须移动文件到目录下");
            }
        }
        // 修改子节点信息
        this.handleChild(file, childNodeList);
        // 更新节点数据
        this.surFileMapper.updateSurFile(file);
    }

    /**
     * 处理子节点
     *
     * @param file
     * @param childNodeList
     */
    private void handleChild(SurFile file, List<SurFile> childNodeList) {
        Long id = file.getId();
        List<SurFile> childNodes = childNodeList.stream().filter(x -> Objects.equals(id, x.getPid())).collect(Collectors.toList());
        if (ObjectUtil.isNotEmpty(childNodes)) {
            for (SurFile childNode : childNodes) {
                childNode.setPids(TcStrUtils.joinStr(file.getPids(), file.getId().toString()));
                this.surFileMapper.updateSurFile(childNode);
                this.handleChild(childNode, childNodeList);
            }
        }
    }
}
